using System;
using System.Collections;
using System.Diagnostics;
using CodeSnippet.Formats.Base;

namespace CodeSnippet.Formats
{
    /// <summary>
    /// Display names for supported formats.
    /// </summary>
    internal static class SupportedFormatTypeDisplayNames
    {
        public const string AutoIt = "AutoIt";
        public const string CCpp = "C/C++";
        public const string ColdFusion = "ColdFusion";
        public const string CSharp = "C#";
        public const string Css = "Cascading Style Sheets";
        public const string Html = "HTML";
        public const string Java = "Java";
        public const string JavaScript = "JavaScript";
        public const string Msh = "MSH";
        public const string Php = "PHP";
        public const string Regex = "Regular Expression";
        public const string Tsql = "TSQL";
        public const string VisualBasic = "Visual Basic";
    }

    /// <summary>
    /// Enumeration of supported formats.
    /// </summary>
    public enum SupportedFormatType
    {
        CSharp = 0,
        JavaScript = 1,
        Html = 2,
        Tsql = 3,
        Msh = 4,
        VisualBasic = 5,
        Css = 6,
        Regex = 7,
        CCpp = 8,
        Java = 9,
        ColdFusion = 10,
        AutoIt = 11,
        Php = 12,
    }

    /// <summary>
    /// Represents a single supported format element.
    /// </summary>
    public class SupportedFormat
    {
        #region Static Fields
        /// <summary>
        /// List of supported formats.
        /// </summary>
        private static readonly ArrayList items = GetSupportedFormatsList();
        #endregion Static Fields

        #region Static Properties
        /// <summary>
        /// Gets the items.
        /// </summary>
        /// <value>The items.</value>
        public static ArrayList Items
        {
            get { return items; }
        }
        #endregion Static Properties

        #region Static Initialization
        /// <summary>
        /// Returns a list of the supported formats.
        /// </summary>
        /// <returns>List of supported formats</returns>
        private static ArrayList GetSupportedFormatsList()
        {
            return new ArrayList
                       {
                           new SupportedFormat(SupportedFormatType.AutoIt, SupportedFormatTypeDisplayNames.AutoIt, typeof (AutoIt)),
                           new SupportedFormat(SupportedFormatType.CCpp, SupportedFormatTypeDisplayNames.CCpp, typeof (CCppFormat)),
                           new SupportedFormat(SupportedFormatType.CSharp, SupportedFormatTypeDisplayNames.CSharp, typeof (CSharpFormat)),
                           new SupportedFormat(SupportedFormatType.ColdFusion, SupportedFormatTypeDisplayNames.ColdFusion, typeof (ColdFusionFormat)),
                           new SupportedFormat(SupportedFormatType.Css, SupportedFormatTypeDisplayNames.Css, typeof (CssFormat)),
                           new SupportedFormat(SupportedFormatType.Html, SupportedFormatTypeDisplayNames.Html, typeof (HtmlFormat)),
                           new SupportedFormat(SupportedFormatType.Java, SupportedFormatTypeDisplayNames.Java, typeof (JavaFormat)),
                           new SupportedFormat(SupportedFormatType.JavaScript, SupportedFormatTypeDisplayNames.JavaScript, typeof (JavaScriptFormat)),
                           new SupportedFormat(SupportedFormatType.Msh, SupportedFormatTypeDisplayNames.Msh, typeof (MshFormat)),
                           new SupportedFormat(SupportedFormatType.Php, SupportedFormatTypeDisplayNames.Php, typeof (PhpFormat)),
                           new SupportedFormat(SupportedFormatType.Regex, SupportedFormatTypeDisplayNames.Regex, typeof (RegexFormat)),
                           new SupportedFormat(SupportedFormatType.Tsql, SupportedFormatTypeDisplayNames.Tsql, typeof (TsqlFormat)),
                           new SupportedFormat(SupportedFormatType.VisualBasic, SupportedFormatTypeDisplayNames.VisualBasic, typeof (VisualBasicFormat))
                       };
        }
        #endregion Static Initialization

        #region Static Operations
        /// <summary>
        /// Predicts the supported format type.
        /// </summary>
        /// <param name="source">The source.</param>
        /// <returns>The corresponding source format type enumeration value.</returns>
        public static SupportedFormatType PredictType(string source)
        {
            SupportedFormatType type = 0;
            var matchCount = 0;
            foreach (SupportedFormat fmt in Items)
            {
                var sf = fmt.NewFormatInstance();
                var count = sf.MatchKeywordCount(source);
                if (count <= matchCount)
                {
                    continue;
                }
                matchCount = count;
                type = fmt.Key;
            }
            return type;
        }
        /// <summary>
        /// Gets the supported format item.
        /// </summary>
        /// <param name="key">The supported format type to match.</param>
        /// <returns><see cref="SupportedFormat"/> instance if found; <c>null</c> otherwise.</returns>
        public static SupportedFormat GetItem(SupportedFormatType key)
        {
            SupportedFormat item = null;
            foreach (SupportedFormat fmt in Items)
            {
                if (fmt.Key != key)
                {
                    continue;
                }
                item = fmt;
                break;
            }
            return item;
        }
        /// <summary>
        /// Gets the supported format type as an item key.
        /// </summary>
        /// <param name="value">The object to test.</param>
        /// <returns>Matching <see cref="SupportedFormatType"/> instance.</returns>
        public static SupportedFormatType GetItemKey(object value)
        {
            var fmt = value as SupportedFormat;
            Debug.Assert(fmt != null);
            return fmt.Key;
        }
        /// <summary>
        /// Gets the item value of the specified object.
        /// </summary>
        /// <param name="value">The object from which to extract the value.</param>
        /// <returns>Value associated to the specified supported format.</returns>
        public static string GetItemValue(object value)
        {
            var fmt = value as SupportedFormat;
            Debug.Assert(fmt != null);
            return fmt.Value;
        }
        #endregion Static Operations

        #region Fields
        private readonly Type _format;
        #endregion Fields

        #region Properties
        /// <summary>
        /// Gets or sets the key.
        /// </summary>
        /// <value>The key.</value>
        public SupportedFormatType Key { get; set; }
        /// <summary>
        /// Gets or sets the value.
        /// </summary>
        /// <value>The value.</value>
        public string Value { get; set; }
        #endregion Properties

        #region Initialization
        /// <summary>
        /// Initializes a new instance of the <see cref="SupportedFormat"/> class.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="value">The value.</param>
        /// <param name="format">The format.</param>
        private SupportedFormat(SupportedFormatType key, string value, Type format)
        {
            Key = key;
            Value = value;
            _format = format;
        }
        #endregion Initialization

        #region Overrides
        /// <summary>
        /// Returns a <see cref="System.String"/> that represents the current <see cref="System.Object"/>.
        /// </summary>
        /// <returns>
        /// A <see cref="System.String"/> that represents the current <see cref="System.Object"/>.
        /// </returns>
        public override string ToString()
        {
            return Value;
        }
        #endregion Overrides

        #region Operations
        /// <summary>
        /// Creates a new format instance dynamically.
        /// </summary>
        /// <returns>The new source format instance.</returns>
        public SourceFormat NewFormatInstance()
        {
            var ci = _format.GetConstructor(new Type[0]);
            Debug.Assert(ci != null, "All Format classes must have a default constructor!");
            return ci.Invoke(null) as SourceFormat;
        }
        #endregion Operations
    }
}